
package org.scalabletype.util;

import java.io.InputStream;
import java.util.Date;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import org.jets3t.service.S3ServiceException;
import org.jets3t.service.model.S3Bucket;

import org.scalabletype.data.DataHelper;
import org.scalabletype.data.Blog;
import org.scalabletype.data.BlogEntry;
import org.scalabletype.data.Media;
import org.scalabletype.data.User;
import org.scalabletype.ws.Copier;

public class MailListener implements Runnable {
	private Store store;
	private String server;
	private String user;
	private String password;

	private Thread listener;
	private S3Bucket bucket;

	public MailListener(String server, String user, String password,
					String accessId, String secretKey, String bucketName) throws NoSuchProviderException, S3ServiceException {
		this.server = server;
		this.user = user;
		this.password = password;
		this.bucket = new S3Bucket(bucketName);
		Copier.initS3(accessId, secretKey);

		Properties props = System.getProperties();
		props.setProperty("mail.pop3.ssl.enable", "true");
		Session session = Session.getDefaultInstance(props, null);
		// -- Get hold of a POP3 message store, and connect to it --
		store = session.getStore("pop3");
	}

	public void startListening() {
		if (listener == null) {
			listener = new Thread(this);
			listener.start();
		}
	}

	public void stopListening() {
		if (listener != null) {
			listener.interrupt();
			listener = null;
		}
	}

	// not meant to be called, except by this class.
	public void run() {
		try {
			if (!store.isConnected()) {
				store.connect(server, 995, user, password);
			}
			// -- Try to get hold of the default folder --
//			Folder folder = store.getDefaultFolder();
//			if (folder == null) throw new Exception("No default folder");
			// -- ...and its INBOX --
			Folder folder = store.getFolder("INBOX");
			if (folder == null) throw new Exception("No POP3 INBOX");
			// -- Open the folder for read only --
			// -- Get the message wrappers and process them --
			while (!Thread.currentThread().isInterrupted()) {
				folder.open(Folder.READ_WRITE);
				Message[] msgs = folder.getMessages();
				if (msgs == null || msgs.length == 0) {
					try { Thread.sleep(5); } catch (Exception ex) { }
				}
				else {
					for (Message msg : msgs) {
						System.out.println("From: "+msg.getFrom()[0]);
						System.out.println("Title: "+msg.getSubject());
						String from = ((InternetAddress)msg.getFrom()[0]).getAddress();
						EntityManager em = DataHelper.getEntityManager();
						Query query = em.createQuery("select object(o) from User o where username = :name");
						query.setParameter("name", from);
						try {
							User u = (User)query.getSingleResult();
							query = em.createQuery("select object(o) from Blog o where o.authors = :user");
							query.setParameter("user", u.getId());
							Blog b = (Blog)query.getSingleResult();

							BlogEntry entry = new BlogEntry();
							entry.setBlog(b.getId());
							String title = msg.getSubject();
							entry.setName(title.toLowerCase().replace(' ', '_'));
							String keyBase = b.getName()+"/"+entry.getName()+"/";
							entry.setTitle(title);
							entry.setDate(new Date());
							entry.setUser(u.getId());
							entry.setS3Key(keyBase+"body");
							em.persist(entry);

							// push content to S3
							Object content = msg.getContent();
							if (content instanceof Multipart) {
								Multipart mmMsg = (Multipart)content;
								System.out.println("Multipart msg has "+mmMsg.getCount()+" parts");
								for (int i=0; i<mmMsg.getCount(); i++) {
									System.out.println("content type : "+mmMsg.getBodyPart(i).getContentType());
									content = mmMsg.getBodyPart(i).getContent();
									if (content instanceof Multipart) {
										Multipart mmMsg2 = (Multipart)content;
										System.out.println("Multipart msg(nested) has "+mmMsg2.getCount()+" parts");
										// in this case, msg seems to have a text and html portion, we're looking for html
										for (int j=0; j<mmMsg2.getCount(); j++) {
											String type = mmMsg2.getBodyPart(j).getContentType();
											System.out.println("    content type : "+type);
											if (type.startsWith("text/html")) {
												Copier.copyToS3(mmMsg2.getBodyPart(j).getInputStream(), -1, this.bucket, entry.getS3Key(), "text/html");
											}
										}
									}
									else {
										// this is probably an attachment and requires media obj
										// but, could be a simpler text and html multi-part. look for that first
										String type = mmMsg.getBodyPart(i).getContentType();
										if (type.startsWith("text/html")) {
											Copier.copyToS3(mmMsg.getBodyPart(i).getInputStream(), -1, this.bucket, entry.getS3Key(), "text/plain");
										}
										else if (type.startsWith("text/plain")) {
											Copier.copyToS3(mmMsg.getBodyPart(i).getInputStream(), -1, this.bucket, entry.getS3Key(), "text/html");
										}
										else {
											// pull the filename out of the content-type to append to keyBase
											String name = type.substring(type.indexOf("name=\"")+6, type.lastIndexOf("\""));
											type = type.substring(0, type.indexOf(";")).trim();
											Media m = new Media();
											m.setEntry(entry.getId());
											m.setContentType(type);
											m.setS3Key(keyBase+name);
											em.persist(m);
											Copier.copyToS3(mmMsg.getBodyPart(i).getInputStream(), -1, this.bucket, m.getS3Key(), type);
										}
									}
								}
							}
							else {
								System.out.println("content type : "+msg.getContentType());
								// throw the data somewhere
								Copier.copyToS3(msg.getInputStream(), -1, this.bucket, entry.getS3Key(), "text/plain");
							}

						} catch (NoResultException ex) {
							// if no use match, assume spam or e-mail from
							// wrong account. delete it and move on.
							System.err.println("Could not find user : "+from);
						}
						msg.setFlag(Flags.Flag.DELETED, true);
					}
				}
				// force expunge of marked (deleted) messages
				folder.close(true);
				try {
					Thread.sleep(5000);
				} catch (InterruptedException ex) {
					break;
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public static void main(String [] args) {
		try {
			DataHelper.initDataHelper(args[0], args[1], "");
//			MailListener ml = new MailListener("pop.gmail.com", "scalabletype@gmail.com", "typeisscalable");
//			ml.run();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}
